urho3dfandomcom-20200214-history
Quad Textures
This method means having four textures in one image like this: Diffuse, normal, specular and height map (the height map is not used in this material). A similar method could be used to pack three textures (which would be better in this case as only three are used) or even more materials in one image file. This has two advantages: * This helps having many textures as Urho3D and the hardware are limited to a certain texture count (for example 8 or 16). -> Four images for the "cost" of one big image. * It's much more convenient to create such an image when using Blender with a technique like this: Creating_Seamless_Procedural_Textures_with_Blender#Bricks_as_a_"Quad_Texture" There is an issue with the mipmaps then using such an image with four textures like displayed above, it results in ugly stripes like these: To fix this the shader code needs to be a bit different and the image needs to be like this: Each of the four tiles is still used as a square which means that half of the texture (the left part of each rectangle) isn't even used. But it's correcting the mipmaps to not create the black stripes seen above. The material file: unit="diffuse" has no real meaning here as this image is not only used for diffuse. This just says that this texture is number 0 which is important for the shader as it expects the one texture at "place" 0. The technique: "Techniques/quad.xml" The GLSL shader (based on the terrain shader and parts from LitBase): "Shaders/quad.glsl" #include "Uniforms.glsl" #include "Samplers.glsl" #include "Transform.glsl" #include "ScreenPos.glsl" #include "Lighting.glsl" #include "Fog.glsl" varying vec4 vTexCoord; varying vec3 vNormal; varying vec4 vTangent; varying vec4 vWorldPos; #ifdef PERPIXEL #ifdef SHADOW varying vec4 vShadowPosNUMCASCADES; #endif #ifdef SPOTLIGHT varying vec4 vSpotPos; #endif #ifdef POINTLIGHT varying vec3 vCubeMaskVec; #endif #else varying vec3 vVertexLight; varying vec4 vScreenPos; #ifdef ENVCUBEMAP varying vec3 vReflectionVec; #endif #if defined(LIGHTMAP) || defined(AO) varying vec2 vTexCoord2; #endif #endif uniform sampler2D sTexture0; void VS() { mat4 modelMatrix = iModelMatrix; vec3 worldPos = GetWorldPos(modelMatrix); gl_Position = GetClipPos(worldPos); vNormal = GetWorldNormal(modelMatrix); vWorldPos = vec4(worldPos, GetDepth(gl_Position)); vec3 tangent = GetWorldTangent(modelMatrix); vec3 bitangent = cross(tangent, vNormal) * iTangent.w; vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy); vTangent = vec4(tangent, bitangent.z); #ifdef PERPIXEL // Per-pixel forward lighting vec4 projWorldPos = vec4(worldPos, 1.0); #ifdef SHADOW // Shadow projection: transform from world space to shadow space for (int i = 0; i < NUMCASCADES; i++) vShadowPosi = GetShadowPos(i, projWorldPos); #endif #ifdef SPOTLIGHT // Spotlight projection: transform from world space to projector texture coordinates vSpotPos = projWorldPos * cLightMatrices0; #endif #ifdef POINTLIGHT vCubeMaskVec = (worldPos - cLightPos.xyz) * mat3(cLightMatrices00.xyz, cLightMatrices01.xyz, cLightMatrices02.xyz); #endif #else // Ambient & per-vertex lighting #if defined(LIGHTMAP) || defined(AO) // If using lightmap, disregard zone ambient light // If using AO, calculate ambient in the PS vVertexLight = vec3(0.0, 0.0, 0.0); vTexCoord2 = iTexCoord2; #else vVertexLight = GetAmbient(GetZonePos(worldPos)); #endif #ifdef NUMVERTEXLIGHTS for (int i = 0; i < NUMVERTEXLIGHTS; ++i) vVertexLight += GetVertexLight(i, worldPos, vNormal) * cVertexLights* 3.rgb; #endif vScreenPos = GetScreenPos(gl_Position); #ifdef ENVCUBEMAP vReflectionVec = worldPos - cCameraPos; #endif #endif } void PS() { vec2 tex_coord_diff=vec2(mod(vTexCoord.x/4.0,0.25),vTexCoord.y); tex_coord_diff.x=0.0625+tex_coord_diff.x*0.5; vec4 diffColor=cMatDiffColor.rgba*texture2D(sTexture0,tex_coord_diff); // Get material specular albedo vec3 specColor = cMatSpecColor.rgb*texture2D(sTexture0,vec2(tex_coord_diff.x+0.5,tex_coord_diff.y)).rgb; // Get normal mat3 tbn = mat3(vTangent.xyz, vec3(vTexCoord.zw, vTangent.w), vNormal); vec3 normal = normalize(tbn * DecodeNormal(texture2D(sTexture0,vec2(tex_coord_diff.x+0.25,tex_coord_diff.y)))); // Get fog factor #ifdef HEIGHTFOG float fogFactor = GetHeightFogFactor(vWorldPos.w, vWorldPos.y); #else float fogFactor = GetFogFactor(vWorldPos.w); #endif #if defined(PERPIXEL) // Per-pixel forward lighting vec3 lightColor; vec3 lightDir; vec3 finalColor; float diff = GetDiffuse(normal, vWorldPos.xyz, lightDir); #ifdef SHADOW diff *= GetShadow(vShadowPos, vWorldPos.w); #endif #if defined(SPOTLIGHT) lightColor = vSpotPos.w > 0.0 ? texture2DProj(sLightSpotMap, vSpotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0); #elif defined(CUBEMASK) lightColor = textureCube(sLightCubeMap, vCubeMaskVec).rgb * cLightColor.rgb; #else lightColor = cLightColor.rgb; #endif #ifdef SPECULAR float spec = GetSpecular(normal, cCameraPosPS - vWorldPos.xyz, lightDir, cMatSpecColor.a); finalColor = diff * lightColor * (diffColor.rgb + spec * specColor * cLightColor.a); #else finalColor = diff * lightColor * diffColor.rgb; #endif #ifdef AMBIENT finalColor += cAmbientColor * diffColor.rgb; finalColor += cMatEmissiveColor; gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a); #else gl_FragColor = vec4(GetLitFog(finalColor, fogFactor), diffColor.a); #endif #elif defined(PREPASS) // Fill light pre-pass G-Buffer float specPower = cMatSpecColor.a / 255.0; gl_FragData0 = vec4(normal * 0.5 + 0.5, specPower); gl_FragData1 = vec4(EncodeDepth(vWorldPos.w), 0.0); #elif defined(DEFERRED) // Fill deferred G-buffer float specIntensity = specColor.g; float specPower = cMatSpecColor.a / 255.0; gl_FragData0 = vec4(GetFog(vVertexLight * diffColor.rgb, fogFactor), 1.0); gl_FragData1 = fogFactor * vec4(diffColor.rgb, specIntensity); gl_FragData2 = vec4(normal * 0.5 + 0.5, specPower); gl_FragData3 = vec4(EncodeDepth(vWorldPos.w), 0.0); #else // Ambient & per-vertex lighting vec3 finalColor = vVertexLight * diffColor.rgb; #ifdef MATERIAL // Add light pre-pass accumulation result // Lights are accumulated at half intensity. Bring back to full intensity now vec4 lightInput = 2.0 * texture2DProj(sLightBuffer, vScreenPos); vec3 lightSpecColor = lightInput.a * lightInput.rgb / max(GetIntensity(lightInput.rgb), 0.001); finalColor += lightInput.rgb * diffColor.rgb + lightSpecColor * specColor; #endif gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a); #endif } See also Terrain Shader with normal, specular and height mapping. '''Another note on the texture sampling issue: '''Theoretically this can be also fixed by doing manual texture sampling in the shader by using texelFetch instead of texture2D, but it was super slow in my tests. My FPS in FullHD dropped from >200 to ~40.